package com.py.payment.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.py.payment.dto.param.PayRecordsParamDto;
import com.py.payment.dto.ret.InfoRetDto;
import com.py.payment.dto.ret.RetDto;
import com.py.payment.entity.PyInfo;
import com.py.payment.entity.PyInfoType;
import com.py.payment.entity.PyPayRecords;
import com.py.payment.mapper.PyInfoMapper;
import com.py.payment.service.PyInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.py.payment.service.PyInfoTypeService;
import com.py.payment.service.PyPayRecordsService;
import com.py.payment.tools.ToolsUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 基础信息表 服务实现类
 * </p>
 *
 * @author py
 * @since 2024-04-17
 */
@Service
public class PyInfoServiceImpl extends ServiceImpl<PyInfoMapper, PyInfo> implements PyInfoService {

    @Autowired
    private PyPayRecordsService payRecordsService;

    @Autowired
    private PyInfoTypeService infoTypeService;

    @Override
    public List<InfoRetDto> getInfoList(PyInfo info) {
        List<InfoRetDto> retDtoList = this.baseMapper.getInfoList(info);
        return retDtoList;
    }

    @Override
    public RetDto getProjectInfo(PyInfo pyInfo){
        RetDto retDto = new RetDto();
        List<InfoRetDto> infoRetDtoList = this.baseMapper.getInfo(pyInfo);
        if(ToolsUtils.isEmpty(infoRetDtoList)){
            return new RetDto();
        }
        List<Integer> infoIdList = infoRetDtoList.stream().map(InfoRetDto::getId).toList();
        List<String> payList = new ArrayList<>();
        Map<Integer,List<PyPayRecords>> map = getMap(infoIdList, pyInfo.getType(),payList);
        List<JSONObject> jsonList = new ArrayList<>();
        infoRetDtoList.forEach(item->{
            List<PyPayRecords> pyPayRecordsList = map.get(item.getId());
            JSONObject json = new JSONObject();
            json.put("bigInfoTitle",item.getBigInfoTitle());
            json.put("preliminaryEstimate",item.getPreliminaryEstimate());
            json.put("id",item.getId());
            json.put("title",item.getTitle());
            json.put("tenderExtimation",item.getTenderExtimation());
            json.put("contractPrice",item.getContractPrice());
            if(ToolsUtils.isNotEmpty(pyPayRecordsList)){
                pyPayRecordsList.forEach(p->{
                    json.put(p.getTitle()+"A",p.getAccountsPayable());
                    json.put(p.getTitle()+"B",p.getNetPayment());
                    json.put(p.getTitle()+"C",p.getRemarks());
                });
            }
            json.put("remarks",item.getRemarks());
            this.cumulative(item,pyPayRecordsList,json);
            jsonList.add(json);
        });
        retDto.setPayTitleList(payList);
        retDto.setInfoList(jsonList);
        return retDto;
    }

    @Override
    public RetDto getOneAmount(PyInfo pyInfo){
        RetDto retDto = new RetDto();
        List<PyInfo> pyInfos = infoList(pyInfo.getType());
        if(ToolsUtils.isEmpty(pyInfos)){
            return new RetDto();
        }
        List<Integer> infoIdList = pyInfos.stream().map(PyInfo::getId).toList();
        List<String> payList = new ArrayList<>();
        Map<Integer,List<PyPayRecords>> map = getMap(infoIdList, pyInfo.getType(),payList);

        List<JSONObject> jsonList = new ArrayList<>();

        pyInfos.forEach(item->{
            List<PyPayRecords> pyPayRecordsList = map.get(item.getId());
            JSONObject json = new JSONObject();
            this.getInfoJson(item,json);
            if(ToolsUtils.isNotEmpty(pyPayRecordsList)){
                pyPayRecordsList.forEach(p->{
                    json.put(p.getTitle(),p.getAccountsPayable());
                });
            }
            json.put("remarks",item.getRemarks());
            this.cumulative(item,pyPayRecordsList,json);
            jsonList.add(json);
        });
        retDto.setPayTitleList(payList);
        retDto.setInfoList(jsonList);
        return retDto;
    }

    @Override
    public RetDto getAllAmount(PyInfo pyInfo){
        RetDto retDto = new RetDto();
        List<PyInfo> pyInfos = infoList(pyInfo.getType());
        if(ToolsUtils.isEmpty(pyInfos)){
            return new RetDto();
        }
        List<Integer> infoIdList = pyInfos.stream().map(PyInfo::getId).toList();
        List<String> payList = new ArrayList<>();
        Map<Integer,List<PyPayRecords>> map = getMap(infoIdList, pyInfo.getType(),payList);

        List<JSONObject> jsonList = new ArrayList<>();
        pyInfos.forEach(item->{
            List<PyPayRecords> pyPayRecordsList = map.get(item.getId());
            JSONObject json = new JSONObject();
            this.getInfoJson(item,json);
            if(ToolsUtils.isNotEmpty(pyPayRecordsList)){
                pyPayRecordsList.forEach(p->{
                    json.put(p.getTitle()+"A",p.getAccountsPayable());
                    json.put(p.getTitle()+"B",p.getNetPayment());
                    json.put(p.getTitle()+"C",p.getRemarks());
                });
            }
            json.put("remarks",item.getRemarks());
            this.cumulative(item,pyPayRecordsList,json);
            jsonList.add(json);
        });
        retDto.setPayTitleList(payList);
        retDto.setInfoList(jsonList);
        return retDto;
    }

    @Override
    public RetDto payList(PyInfo pyInfo) {
        RetDto retDto = new RetDto();
        QueryWrapper<PyInfoType> pyInfoTypeQueryWrapper = new QueryWrapper<>();
        pyInfoTypeQueryWrapper.eq("status",1);
        List<PyInfoType> infoTypeList = this.infoTypeService.list(pyInfoTypeQueryWrapper);
        List<PyPayRecords> payRecordsList = this.baseMapper.payList(pyInfo);

        List<String> payTileList = new ArrayList<>();
        Map<Integer,List<PyPayRecords>> map = new HashMap<>();
        payRecordsList.forEach(item->{
            if(map.containsKey(item.getType())){
                map.get(item.getType()).add(item);
            } else {
                List<PyPayRecords> payRecords = new ArrayList<>();
                payRecords.add(item);
                map.put(item.getType(),payRecords);
            }
            if(!payTileList.contains(item.getTitle())){
                payTileList.add(item.getTitle());
            }
        });
        List<JSONObject> jsonList = new ArrayList<>();
        infoTypeList.forEach(item->{
            JSONObject json = new JSONObject();
            json.put("title",item.getTitle());
            List<PyPayRecords> list = map.get(item.getId());
            if(ToolsUtils.isNotEmpty(list)){
                list.forEach(i->{
                    BigDecimal accountsPayable = new BigDecimal(ToolsUtils.isEmpty(i.getAccountsPayable())?"0":i.getAccountsPayable()).setScale(2,RoundingMode.HALF_UP);
                    BigDecimal netPayment = new BigDecimal(ToolsUtils.isEmpty(i.getNetPayment())?"0":i.getNetPayment()).setScale(2,RoundingMode.HALF_UP);
                    json.put(i.getTitle()+"A",accountsPayable.compareTo(BigDecimal.ZERO)==0?"-":accountsPayable.toPlainString());
                    json.put(i.getTitle()+"B",netPayment.compareTo(BigDecimal.ZERO)==0?"-":netPayment.toPlainString());
                });
            }
            json.put("remarks","");
            jsonList.add(json);
        });
        retDto.setInfoList(jsonList);
        retDto.setPayTitleList(payTileList);

        return retDto;
    }

    private List<PyInfo> infoList(Integer type){
        QueryWrapper<PyInfo> infoQueryWrapper = new QueryWrapper<>();
        infoQueryWrapper.eq("type",type);
        List<PyInfo> list = this.list(infoQueryWrapper);
        return list;
    }

    private Map<Integer,List<PyPayRecords>> getMap(List<Integer> idList,Integer type,List<String> payList){
        Map<Integer,List<PyPayRecords>> map = new HashMap<>();
        QueryWrapper<PyPayRecords> payRecordsQueryWrapper = new QueryWrapper<>();
        payRecordsQueryWrapper.eq("type",type);
        payRecordsQueryWrapper.in("info_id",idList);
        payRecordsQueryWrapper.orderByAsc("id");
        PayRecordsParamDto paramDto = new PayRecordsParamDto();
        paramDto.setType(type);
        paramDto.setInfoIdList(idList);
        List<PyPayRecords> payRecordsList = this.payRecordsService.getPayRecordList(paramDto);
        payRecordsList.forEach(item->{
            if(map.containsKey(item.getInfoId())){
                map.get(item.getInfoId()).add(item);
            } else {
                List<PyPayRecords> pyPayRecordsList = new ArrayList<>();
                pyPayRecordsList.add(item);
                map.put(item.getInfoId(),pyPayRecordsList);
            }
        });

        payRecordsList.forEach(item->{
            if(!payList.contains(item.getTitle())){
                payList.add(item.getTitle());
            }
        });
        return map;
    }

    private PyPayRecords getCumulative(Integer infoId,Integer type){
        QueryWrapper<PyPayRecords> payRecordsQueryWrapper = new QueryWrapper<>();
        payRecordsQueryWrapper.select("IFNULL(sum(accounts_payable) ,0)as 'accountsPayable',IFNULL(sum(net_payment),0) as 'netPayment'");
        payRecordsQueryWrapper.eq("info_id",infoId);
        payRecordsQueryWrapper.eq("type",type);
        PyPayRecords pay = this.payRecordsService.getOne(payRecordsQueryWrapper);
        if(ToolsUtils.isNotEmpty(pay)){
            return pay;
        } else{
            return new PyPayRecords();
        }
    }

    private void getInfoJson(PyInfo info,JSONObject json){
        json.put("id",info.getId());
        json.put("title",info.getTitle());
        json.put("preliminaryEstimate",info.getPreliminaryEstimate());
        json.put("tenderExtimation",info.getTenderExtimation());
        json.put("contractPrice",info.getContractPrice());
    }

    private void cumulative(PyInfo info,List<PyPayRecords> pyPayRecordsList,JSONObject json){
        PyPayRecords pay = getCumulative(info.getId(),info.getType());
        BigDecimal cumulativeAccountsPayable = new BigDecimal(ToolsUtils.isEmpty(pay.getAccountsPayable())?"0":pay.getAccountsPayable());
        BigDecimal cumulativeNetPayment = new BigDecimal(ToolsUtils.isEmpty(pay.getNetPayment())?"0":pay.getNetPayment());
        BigDecimal cumulativeDeduction = cumulativeAccountsPayable.subtract(cumulativeNetPayment);
        BigDecimal contractPrice = new BigDecimal(ToolsUtils.isEmpty(info.getContractPrice())?"0":info.getContractPrice());
        BigDecimal proportion = BigDecimal.ZERO;
        if(contractPrice.compareTo(BigDecimal.ZERO)!=0){
            proportion = cumulativeAccountsPayable.divide(contractPrice,4, RoundingMode.HALF_UP).multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP);
        }
        BigDecimal cumulativeHave = BigDecimal.ZERO;
        if(ToolsUtils.isNotEmpty(pyPayRecordsList)){
            PyPayRecords i = pyPayRecordsList.get(0);
            if(ToolsUtils.isNotEmpty(i.getAccountsPayable())){
                cumulativeHave = new BigDecimal(ToolsUtils.isEmpty(i.getAccountsPayable())?"0":i.getAccountsPayable());
            }
        }
        cumulativeHave = cumulativeNetPayment.add(cumulativeHave);
        NumberFormat numberInstance = DecimalFormat.getNumberInstance();

//        json.put("cumulativeAccountsPayable",cumulativeAccountsPayable.setScale(2,RoundingMode.HALF_UP).toPlainString());
//        json.put("cumulativeNetPayment",cumulativeNetPayment.setScale(2,RoundingMode.HALF_UP).toPlainString());
//        json.put("cumulativeDeduction",cumulativeDeduction.setScale(2,RoundingMode.HALF_UP).toPlainString());
//        json.put("cumulativeHave",cumulativeHave.setScale(2,RoundingMode.HALF_UP).toPlainString());

        json.put("cumulativeAccountsPayable",cumulativeAccountsPayable.compareTo(BigDecimal.ZERO)==0?"-":numberInstance.format(cumulativeAccountsPayable.setScale(2,RoundingMode.HALF_UP)));
        json.put("cumulativeNetPayment",cumulativeNetPayment.compareTo(BigDecimal.ZERO)==0?"-":numberInstance.format(cumulativeNetPayment.setScale(2,RoundingMode.HALF_UP)));
        json.put("cumulativeDeduction",cumulativeDeduction.compareTo(BigDecimal.ZERO)==0?"-":numberInstance.format(cumulativeDeduction.setScale(2,RoundingMode.HALF_UP)));
        json.put("cumulativeHave",cumulativeHave.compareTo(BigDecimal.ZERO)==0?"-":numberInstance.format(cumulativeHave.setScale(2,RoundingMode.HALF_UP)));
        json.put("proportion",proportion.compareTo(BigDecimal.ZERO)==0?"-":proportion.setScale(2,RoundingMode.HALF_UP).toPlainString()+"%");
    }
}
